package com.gsi.webstore.platform.storefront.capi.calculation;

import java.util.Arrays;
import java.util.List;

import com.gsi.webstore.platform.adapter.taxes_duties_fees.capi.calculation.ComputedErrorItem;
import com.gsi.webstore.platform.adapter.taxes_duties_fees.capi.calculation.ComputedTaxInfoItem;
import com.gsi.webstore.platform.adapter.taxes_duties_fees.capi.v1.CalculateTotalPerDutyTypeRule;
import com.gsi.webstore.platform.adapter.taxes_duties_fees.capi.v1.CalculateTotalPerSurchargeTypeRule;
import com.gsi.webstore.platform.adapter.taxes_duties_fees.capi.v1.CalculateTotalPerTaxTypeRule;
import com.gsi.webstore.platform.adapter.taxes_duties_fees.capi.v1.DetermineRoughPaymentCostsRule;
import com.gsi.webstore.platform.adapter.taxes_duties_fees.capi.v1.TaxesDutiesCalculationServiceRule;
import com.gsi.webstore.platform.storefront.internal.calculation.rule.CustomCalculateSingleProductBasePricesRule;
import com.intershop.beehive.bts.capi.orderprocess.calculation.ComputedProductLineItem;
import com.intershop.beehive.bts.capi.orderprocess.calculation.ComputedServiceLineItem;
import com.intershop.beehive.bts.capi.orderprocess.calculation.LineItemCtnrCalculationRuleGroup;
import com.intershop.beehive.bts.capi.orderprocess.calculation.LineItemCtnrCalculationRuleSet;
import com.intershop.beehive.bts.capi.orderprocess.calculation.rules.CalculateSingleProductBasePricesRule;
import com.intershop.beehive.bts.capi.orderprocess.calculation.rules.CopyMoneyValueIntoNativeAttributeRule;
import com.intershop.beehive.bts.capi.orderprocess.calculation.rules.CopyMoneyValueIntoNativeAttributeRule.NativeAttribute;
import com.intershop.beehive.bts.capi.orderprocess.calculation.rules.CreateChildProductItemsRule;
import com.intershop.beehive.bts.capi.orderprocess.calculation.rules.CreateInitialProductItemsRule;
import com.intershop.beehive.bts.capi.orderprocess.calculation.rules.DetermineProductItemsWithPriceRule;
import com.intershop.beehive.bts.capi.payment.calculation.CalculatePaymentSurchargesRule;
import com.intershop.beehive.bts.capi.payment.calculation.ComputedPaymentInstrumentItem;
import com.intershop.beehive.bts.capi.payment.calculation.CopyMoneyAmountToPII;
import com.intershop.beehive.bts.capi.payment.calculation.DeleteObsoletePIIs;
import com.intershop.beehive.bts.capi.payment.calculation.DistributeBasketTotalAmountRule;
import com.intershop.component.foundation.capi.spreadsheet.CellSelector.Cell;
import com.intershop.component.foundation.capi.spreadsheet.CellSelector.Group;
import com.intershop.component.foundation.capi.spreadsheet.CellSelector.GroupSet;
import com.intershop.component.foundation.capi.spreadsheet.CellSelector.SubGroup;
import com.intershop.component.foundation.capi.spreadsheet.ComputedMoneyItem;
import com.intershop.component.foundation.capi.spreadsheet.ComputedPercentageItem;
import com.intershop.component.foundation.capi.spreadsheet.ComputedQuantityItem;
import com.intershop.component.foundation.capi.spreadsheet.rules.AddMoneyRule;
import com.intershop.component.foundation.capi.spreadsheet.rules.CalculateGroupAddMoneyRule;
import com.intershop.component.foundation.capi.spreadsheet.rules.ComputeQuantityRule;
import com.intershop.component.foundation.capi.spreadsheet.rules.DummyRule;
import com.intershop.component.foundation.capi.spreadsheet.rules.MultiplyMoneyWithQuantityRule;
import com.intershop.component.foundation.capi.spreadsheet.rules.RoundMoneyRule;
import com.intershop.component.foundation.capi.spreadsheet.rules.SubtractMoneyRule;
import com.intershop.component.gifting.capi.order.LineItemConstants;
import com.intershop.component.marketing.capi.promotion.action.ItemPercentageOffDiscount;
import com.intershop.component.marketing.capi.promotion.action.ItemTargetPriceDiscount;
import com.intershop.component.marketing.capi.promotion.action.ItemValueOffDiscount;
import com.intershop.component.marketing.capi.promotion.action.ShippingPercentageOffDiscount;
import com.intershop.component.marketing.capi.promotion.action.ShippingTargetPriceDiscount;
import com.intershop.component.marketing.capi.promotion.action.ShippingValueOffDiscount;
import com.intershop.component.marketing.capi.promotion.calculation.rule.ComputedDiscountItem;
import com.intershop.component.marketing.capi.promotion.calculation.rule.ComputedDynamicMessageDiscountItem;
import com.intershop.component.marketing.capi.promotion.calculation.rule.PromotionCalculationRule;
import com.intershop.component.marketing.internal.promotion.action.descriptor.OrderPercentageOffDiscount;
import com.intershop.component.marketing.internal.promotion.action.descriptor.OrderValueOffDiscount;
import com.intershop.component.marketing.internal.promotion.action.executor.FreeGiftOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.HiddenGiftOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.ItemPercentageOffOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.ItemTargetPriceOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.ItemValueOffOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.OrderPercentageOffOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.OrderValueOffOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.ShippingPercentageOffOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.ShippingTargetPriceOutParams;
import com.intershop.component.marketing.internal.promotion.action.executor.ShippingValueOffOutParams;
import com.intershop.component.shipping.capi.shippingchargecalculator.ComputedShippingBucketItem;
import com.intershop.component.shipping.capi.shippingchargecalculator.ComputedShippingExtraChargeItem;
import com.intershop.component.shipping.capi.shippingchargecalculator.rule.ShippingBucketCreationRule;
import com.intershop.component.shipping.capi.shippingchargecalculator.rule.ShippingExtraChargeCalculatorRule;
import com.intershop.component.shipping.capi.shippingchargecalculator.rule.ShippingPLIChargeCalculatorRule;
import com.intershop.component.warranty.capi.orderprocess.calculation.rules.CreateWarrantyPricesRule;
import com.intershop.sellside.appbase.b2c.capi.calculation.BonusPointCalculation;
import com.intershop.sellside.appbase.b2c.capi.order.ProductConfigurationLineItemBO;
import com.intershop.sellside.appbase.b2c.capi.order.WarrantyLineItemBO;

@SuppressWarnings("unchecked")
public class GSIGrossBasedCalculation_V2 extends LineItemCtnrCalculationRuleSet
{
    public static final Pli PLI = new Pli("pli");
    public static final Shipping SHIPPING = new Shipping("shipping");
    public static final BonusPoint BONUS_POINT = new BonusPoint("bonusPoint");
    public static final Tax TAX = new Tax("tax");
    public static final Total TOTAL = new Total("total");
    public static final Promotion PROMOTION = new Promotion("promotion");
    public static final Order ORDER = new Order("order");
    public static final Payment PAYMENT = new Payment("payment");
    public static final Configuration CONFIGURATION = new Configuration("configuration");
    public static final Gifting GIFTING = new Gifting("gifting");
    public static final Warranty WARRANTY = new Warranty("warranty");

    public static class Shipping extends LineItemCtnrCalculationRuleGroup
    {
        /*** Costs for geographical extra charges/fees ***/
        public final GroupSet<ComputedShippingExtraChargeItem> PLI_GEOGRAPHICAL_SURCHARGES = groupset("PLI_GEOGRAPHICAL_SURCHARGES.#");
        public final GroupSet<ComputedMoneyItem> PLI_GEOGRAPHICAL_SURCHARGE_COSTS = groupset("PLI_GEOGRAPHICAL_SURCHARGE_COSTS.#");

        /*** Taxes applied to geographical extra charges/fees ***/
        public final GroupSet<ComputedTaxInfoItem> PLI_GEOGRAPHICAL_SURCHARGE_TAX_INFO = groupset("PLI_GEOGRAPHICAL_SURCHARGE_TAX_INFO.#");
        public final GroupSet<ComputedMoneyItem> PLI_GEOGRAPHICAL_SURCHARGE_TAX_COSTS = groupset("PLI_GEOGRAPHICAL_SURCHARGE_TAX_COSTS.#");

        /*** Costs for import extra charges/fees ***/
        public final GroupSet<ComputedShippingExtraChargeItem> PLI_IMPORT_SURCHARGES = groupset("PLI_IMPORT_SURCHARGES.#");
        public final GroupSet<ComputedMoneyItem> PLI_IMPORT_SURCHARGE_COSTS = groupset("PLI_IMPORT_SURCHARGE_COSTS.#");

        /*** Taxes applied to import extra charges/fees ***/
        public final GroupSet<ComputedTaxInfoItem> PLI_IMPORT_SURCHARGE_TAX_INFO = groupset("PLI_IMPORT_SURCHARGE_TAX_INFO.#");
        public final GroupSet<ComputedMoneyItem> PLI_IMPORT_SURCHARGE_TAX_COSTS = groupset("PLI_IMPORT_SURCHARGE_TAX_COSTS.#");

        public final Group<ComputedShippingBucketItem> BUCKETS = group("BUCKETS");
        public final Group<ComputedMoneyItem> BUCKET_COSTS = group("BUCKET_COSTS");
        /** W/O discounts */
        public final Group<ComputedMoneyItem> PLI_GROSS_BASE_COSTS = group("PLI_GROSS_BASE_COSTS");
        /** with discounts */
        public final Group<ComputedMoneyItem> PLI_GROSS_COSTS = group("PLI_GROSS_COSTS");
        public final Group<ComputedMoneyItem> PLI_NET_BASE_COSTS = group("PLI_NET_BASE_COSTS");

        /*** Taxes applied to line item shipping costs ***/
        public final GroupSet<ComputedPercentageItem> PLI_TAX_RATES = groupset("PLI_TAX_RATES.#");
        public final GroupSet<ComputedMoneyItem> PLI_TAX_COSTS = groupset("PLI_TAX_COSTS.#");
        public final GroupSet<ComputedTaxInfoItem> PLI_TAX_INFO = groupset("PLI_TAX_INFO.#");
        public final GroupSet<ComputedTaxInfoItem> DISCOUNT_TAX_INFOS = groupset("DISCOUNT_TAX_INFOS.#");

        private final Group<ComputedMoneyItem> TAX_PLI_COSTS = group("TAX_PLI_PRICES");

        public final Group<ComputedMoneyItem> SUBTOTALS = group("SUBTOTALS");

        public final Cell<ComputedMoneyItem> TOTALS_DISCOUNT = cell(SUBTOTALS, "Discount");
        public final Cell<ComputedMoneyItem> TOTALS_GROSS = cell(SUBTOTALS, "ShippingGross");
        public final Cell<ComputedMoneyItem> TOTALS_NET = cell(SUBTOTALS, "ShippingNet");
        public final Cell<ComputedMoneyItem> TOTALS_BASE_NET = cell(SUBTOTALS, "ShippingNet");
        public final Cell<ComputedMoneyItem> TOTALS_TAX = cell(SUBTOTALS, "Tax");

        public final GroupSet<ComputedShippingExtraChargeItem> PLI_OVERRIDE = groupset("PLI_OVERRIDE.#");
        public final GroupSet<ComputedMoneyItem> PLI_OVERRIDE_COST = groupset("PLI_OVERRIDE_COST.#");
        public final GroupSet<ComputedShippingExtraChargeItem> PLI_SURCHARGES = groupset("PLI_SURCHARGES.#");
        public final GroupSet<ComputedMoneyItem> PLI_SURCHARGE_COSTS = groupset("PLI_SURCHARGE_COSTS.#");

        public final GroupSet<ComputedShippingExtraChargeItem> BUCKET_OVERRIDE = groupset("BUCKET_OVERRIDE.#");
        public final GroupSet<ComputedMoneyItem> BUCKET_OVERRIDE_COST = groupset("BUCKET_OVERRIDE_COST.#");
        public final GroupSet<ComputedShippingExtraChargeItem> BUCKET_SURCHARGES = groupset("BUCKET_SURCHARGES.#");
        public final GroupSet<ComputedMoneyItem> BUCKET_SURCHARGE_COSTS = groupset("BUCKET_SURCHARGE_COSTS.#");

        public Shipping(final String prefix)
        {
            super(prefix);
        }

        @Override
        protected void defineRules()
        {
            addRule("shippingBuckets", new ShippingBucketCreationRule(out(BUCKETS), in(PLI.PLIS)));
            addRule("shippingPLIExtraCharge", new ShippingExtraChargeCalculatorRule(out(BUCKET_OVERRIDE),
                            out(BUCKET_OVERRIDE_COST), out(BUCKET_SURCHARGES), out(BUCKET_SURCHARGE_COSTS),
                            out(PLI_OVERRIDE), out(PLI_OVERRIDE_COST), out(PLI_SURCHARGES), out(PLI_SURCHARGE_COSTS),
                            out(PLI_GEOGRAPHICAL_SURCHARGES), out(PLI_GEOGRAPHICAL_SURCHARGE_COSTS),
                            out(PLI_IMPORT_SURCHARGES), out(PLI_IMPORT_SURCHARGE_COSTS), in(PLI.PLIS),
                            in(PLI.GROSS_BASE_PRICES), in(BUCKETS)));
            addRule("shippingPLICharge", new ShippingPLIChargeCalculatorRule(out(PLI_GROSS_BASE_COSTS), out(BUCKET_COSTS),
                            in(PLI_OVERRIDE), in(PLI_OVERRIDE_COST), in(PLI_SURCHARGES), in(PLI_SURCHARGE_COSTS),
                            in(BUCKET_OVERRIDE), in(BUCKET_OVERRIDE_COST), in(BUCKET_SURCHARGES),
                            in(BUCKET_SURCHARGE_COSTS), in(PLI.GROSS_BASE_PRICES), in(BUCKETS)));

            addRule("calculateShippingGrossTotal", new AddMoneyRule(out(TOTALS_GROSS), in(PLI_GROSS_BASE_COSTS)));
            addRule("calculateShippingTaxTotal", new AddMoneyRule(out(TOTALS_TAX), in(PLI_TAX_COSTS)));
            addRule("calculateShippingPLITaxes", new AddMoneyRule(out(TAX_PLI_COSTS), in(PLI_TAX_COSTS)));
            addRule("calculationShippingPLINetCharge", new SubtractMoneyRule(out(PLI_NET_BASE_COSTS), in(PLI_GROSS_BASE_COSTS), in(TAX_PLI_COSTS)));

            addRule("calculateTotalPerSurchargeType", new CalculateTotalPerSurchargeTypeRule(
                            out(TOTAL.SURCHARGE_PER_TYPE), in(PLI_GEOGRAPHICAL_SURCHARGES),
                            in(PLI_GEOGRAPHICAL_SURCHARGE_COSTS), in(PLI_IMPORT_SURCHARGES),
                            in(PLI_IMPORT_SURCHARGE_COSTS)));

            addRule("calculateNetShippingCosts", new SubtractMoneyRule(out(TOTALS_NET), in(TOTALS_GROSS), in(TOTALS_TAX)));
        }

    }

    public static class Total extends LineItemCtnrCalculationRuleGroup
    {
        /*** Totals ***/
        public final Group<ComputedMoneyItem>         TOTALS                    = group("TOTALS");
        public final Cell<ComputedMoneyItem>          DISCOUNT           = cell(TOTALS, "Discount");
        public final Cell<ComputedMoneyItem>          TOTALS_SHIPPING           = cell(TOTALS, "Shipping");
        public final Cell<ComputedMoneyItem>          NET                = cell(TOTALS, "Net");
        public final Cell<ComputedMoneyItem>          SURCHARGE          = cell(TOTALS, "Surcharge");
        public final Cell<ComputedMoneyItem>          TAX                = cell(TOTALS, "Tax");
        public final Cell<ComputedMoneyItem>          DUTY               = cell(TOTALS, "Duty");
        public final Cell<ComputedMoneyItem>          GROSS              = cell(TOTALS, "Gross");
        public final Cell<ComputedMoneyItem>          BPP                = cell(TOTALS, "BonusPointPrice");
        public final Cell<ComputedMoneyItem>          BPV                = cell(TOTALS, "BonusPointValue");
        
        /** The totals tax = sum of all taxes */
        public final Cell<ComputedMoneyItem> TOTALS_TAX_WITHOUT_PAYMENTTAX = cell(TOTALS, "Tax_without_paymenttax");
        /** The totals gross = totals net + taxes. */
        public final Cell<ComputedMoneyItem> TOTALS_GROSS_WITHOUT_PAYMENTSURCHARGES = cell(TOTALS, "Gross_without_paymentsurcharges");
        /** The totals gross minus limited tender total amount */
        public final Cell<ComputedMoneyItem> TOTALS_GROSS_MINUS_LIMITED_PII = cell(TOTALS, "Gross_without_limited_tenders");

        /*** Additional totals for UI ***/
        public final Group<ComputedMoneyItem>         TAX_PER_TYPE       = group("TAX_PER_TYPE");
        public final Group<ComputedMoneyItem>         DUTY_PER_TYPE      = group("DUTY_PER_TYPE");
        public final Group<ComputedMoneyItem>         SURCHARGE_PER_TYPE = group("SURCHARGE_PER_TYPE");
        public final Cell<ComputedMoneyItem>          DUTY_SURCHARGE     = cell(TOTALS, "Duty_Surharge");
        public final Cell<ComputedMoneyItem>          TAX_DUTY_SURCHARGE = cell(TOTALS, "Tax_Duty_Surcharge");

        public Total(final String prefix)
        {
            super(prefix);
        }

        @Override
        protected void defineRules()
        {
            addRule("copyTotalGrossPricePC", new CopyMoneyValueIntoNativeAttributeRule(
                            NativeAttribute.GrandTotalGrossPricePC, in(GROSS)));
            addRule("copyTotalNetPricePC", new CopyMoneyValueIntoNativeAttributeRule(
                            NativeAttribute.GrandTotalNetPricePC, in(NET)));
            addRule("copyTotalTaxPC", new CopyMoneyValueIntoNativeAttributeRule(NativeAttribute.GrandTotalTaxPC,
                            in(TAX)));
            
            addRule("calculateTaxTotalWithoutPayment", new AddMoneyRule(out(TOTALS_TAX_WITHOUT_PAYMENTTAX), in(ORDER.VALUE_TAX),
                            in(GIFTING.PLI_TAXES), in(CONFIGURATION.PLI_TAXES), in(WARRANTY.PLI_TAXES)));
             
            addRule("calculateGrossTotalWithoutPayment", new AddMoneyRule(out(TOTALS_GROSS_WITHOUT_PAYMENTSURCHARGES),
                            in(ORDER.VALUE_GROSS), in(SHIPPING.TOTALS_GROSS), in(SHIPPING.TOTALS_DISCOUNT),
                            in(CONFIGURATION.TOTALS_GROSS), in(GIFTING.TOTALS_GROSS)));
            
            addRule("calculateGrossTotal", new AddMoneyRule(out(GROSS), in(TOTALS_GROSS_WITHOUT_PAYMENTSURCHARGES),
                            in(PAYMENT.TOTALS_COST)));
            addRule("calculateTaxTotal", new AddMoneyRule(out(TAX), in(TOTALS_TAX_WITHOUT_PAYMENTTAX), in(PAYMENT.TOTALS_TAX)));
            
            addRule("calculateGrossMinusLimited", new SubtractMoneyRule(out(TOTALS_GROSS_MINUS_LIMITED_PII),
                            in(GROSS), in(PAYMENT.TOTALS_COVERED_LIMITED)));
            
            addRule("calculateNetTotal", new SubtractMoneyRule(out(NET), in(GROSS),
                            in(TAX_DUTY_SURCHARGE)));

            addRule("calulateOrderValueDuty", new AddMoneyRule(out(DUTY), in(PLI.SUBTOTALS_DUTY)));
            addRule("calulateOrderValueSurcharge", new AddMoneyRule(out(SURCHARGE), in(PLI.SUBTOTALS_SURCHARGE)));

            addRule("calulateOrderValueDutySurcharge", new AddMoneyRule(out(DUTY_SURCHARGE),
                            in(SURCHARGE), in(DUTY)));
            addRule("calulateOrderValueTaxDutySurcharge", new AddMoneyRule(out(TAX_DUTY_SURCHARGE),
                            in(TAX), in(DUTY_SURCHARGE)));
        }
    }

    public static class Promotion extends LineItemCtnrCalculationRuleGroup
    {
        public final GroupSet<ComputedDiscountItem> APPLIED_DISCOUNTS = groupset("APPLIED_DISCOUNTS_");
        public final GroupSet<ComputedDynamicMessageDiscountItem> DYNAMIC_MESSAGE_DISCOUNTS = groupset("DYNAMIC_MESSAGE_DISCOUNTS_");
        public final Group<ComputedMoneyItem> APPLIED_DISCOUNT_AMOUNTS = group("APPLIED_DISCOUNT_AMOUNTS");

        public final List<String> ITEMDISCOUNTS =  Arrays.asList(ItemTargetPriceDiscount.ID, ItemPercentageOffDiscount.ID, ItemValueOffDiscount.ID);
        public final Group<ComputedDiscountItem> APPLIED_DISCOUNTS_ONITEM = group(APPLIED_DISCOUNTS, "ONITEM");
        public final Group<ComputedDynamicMessageDiscountItem> DYNAMIC_MESSAGE_DISCOUNTS_ONITEM = group(DYNAMIC_MESSAGE_DISCOUNTS, "ONITEM");
        public final GroupSet<ComputedMoneyItem> GROSS_PLI_DISCOUNTS_ONITEM = groupset("GROSS_PLI_DISCOUNTS_ONITEM");
        /** all tax amounts for discounts (including shipping, pli and order discounts)*/
        public final GroupSet<ComputedMoneyItem> NET_DISCOUNT_AMOUNTS = groupset("NET_DISCOUNT_AMOUNTS.#");

        public final GroupSet<ComputedMoneyItem> PLI_SINGLE_DISCOUNTS_ONITEM = groupset("PLI_SINGLE_DISCOUNTS_ONITEM");
        public final GroupSet<ComputedMoneyItem> PLI_DISCOUNTED_ITEM_TARGET_PRICES_ONITEM = groupset("PLI_DISCOUNTED_ITEM_TARGET_PRICES_ONITEM");
        public final GroupSet<ComputedPercentageItem> PLI_DISCOUNTED_ITEM_PERCENTAGES_ONITEM = groupset("PLI_DISCOUNTED_ITEM_PERCENTAGES_ONITEM");
        public final GroupSet<ComputedQuantityItem> PLI_DISCOUNTED_ITEM_QUANTITIES_ONITEM = groupset("PLI_DISCOUNTED_ITEM_QUANTITIES_ONITEM");

        public final List<String> ORDERVALUEDISCOUNTS =  Arrays.asList(OrderPercentageOffDiscount.ID, OrderValueOffDiscount.ID);
        public final Group<ComputedDiscountItem> APPLIED_DISCOUNTS_ONORDERVALUE = group(APPLIED_DISCOUNTS, "ONORDERVALUE");
        public final Group<ComputedDynamicMessageDiscountItem> DYNAMIC_MESSAGE_DISCOUNTS_ONORDERVALUE = group(DYNAMIC_MESSAGE_DISCOUNTS, "ONORDERVALUE");
        public final GroupSet<ComputedMoneyItem> ORDER_VALUE_DISCOUNTS_ONORDERVALUE = groupset("ORDER_VALUE_DISCOUNTS_ONORDERVALUE");
        private final GroupSet<ComputedPercentageItem> ORDER_PERCENTAGES_ONORDERVALUE = groupset("ORDER_DISCOUNTED_PERCENTAGES_ONORDERVALUE");
        public final GroupSet<ComputedMoneyItem> PLI_DISCOUNTS_ONORDERVALUE = groupset("PLI_DISCOUNTS_ONORDERVALUE");
        public final GroupSet<ComputedMoneyItem> PLI_SINGLE_DISCOUNTS_ONORDERVALUE = groupset("PLI_SINGLE_DISCOUNTS_ONORDERVALUE");
        public final GroupSet<ComputedQuantityItem> PLI_DISCOUNTED_ITEM_QUANTITIES_ONORDERVALUE = groupset("PLI_DISCOUNTED_ITEM_QUANTITIES_ONORDERVALUE");

        public final GroupSet<ComputedProductLineItem> BONUS_PRODUCTS_ONGIFT = groupset("BONUS_PRODUCTS_ONGIFT");
        public final Group<ComputedDiscountItem> APPLIED_DISCOUNTS_ONGIFT = group(APPLIED_DISCOUNTS, "ONGIFT");
        public final Group<ComputedDynamicMessageDiscountItem> DYNAMIC_MESSAGE_DISCOUNTS_ONGIFT = group(DYNAMIC_MESSAGE_DISCOUNTS, "ONGIFT");
        public final GroupSet<ComputedQuantityItem> DISCOUNTED_ITEM_QUANTITIES_ONGIFT = groupset("DISCOUNTED_ITEM_QUANTITIES_ONGIFT");
        private final GroupSet<ComputedMoneyItem> DISCOUNTED_ITEM_TARGET_PRICES_ONGIFT = groupset("DISCOUNTED_ITEM_TARGET_PRICES_ONGIFT");
        private final GroupSet<ComputedMoneyItem> SINGLE_ITEM_DISCOUNTS_ONGIFT = groupset("SINGLE_ITEM_DISCOUNTS_ONGIFT");
        private final GroupSet<ComputedMoneyItem> ITEM_DISCOUNTS_ONGIFT = groupset("ITEM_DISCOUNTS_ONGIFT");

        public final GroupSet<ComputedProductLineItem> BONUS_PRODUCTS_ONHIDDENGIFT = groupset("BONUS_PRODUCTS_ONHIDDENGIFT");
        public final Group<ComputedDiscountItem> APPLIED_DISCOUNTS_ONHIDDENGIFT = group(APPLIED_DISCOUNTS, "ONHIDDENGIFT");
        public final Group<ComputedDynamicMessageDiscountItem> DYNAMIC_MESSAGE_DISCOUNTS_ONHIDDENGIFT = group(DYNAMIC_MESSAGE_DISCOUNTS, "ONHIDDENGIFT");
        public final GroupSet<ComputedQuantityItem> DISCOUNTED_ITEM_QUANTITIES_ONHIDDENGIFT = groupset("DISCOUNTED_ITEM_QUANTITIES_ONHIDDENGIFT");
        private final GroupSet<ComputedMoneyItem> DISCOUNTED_ITEM_TARGET_PRICES_ONHIDDENGIFT = groupset("DISCOUNTED_ITEM_TARGET_PRICES_ONHIDDENGIFT");
        private final GroupSet<ComputedMoneyItem> SINGLE_ITEM_DISCOUNTS_ONHIDDENGIFT = groupset("SINGLE_ITEM_DISCOUNTS_ONHIDDENGIFT");
        private final GroupSet<ComputedMoneyItem> ITEM_DISCOUNTS_ONHIDDENGIFT = groupset("ITEM_DISCOUNTS_ONHIDDENGIFT");

        public final List<String> SHIPPINGISCOUNTS =  Arrays.asList(ShippingPercentageOffDiscount.ID, ShippingValueOffDiscount.ID, ShippingTargetPriceDiscount.ID);
        public final Group<ComputedDiscountItem> APPLIED_DISCOUNTS_ONSHIPPING = group(APPLIED_DISCOUNTS, "ONSHIPPING");
        public final Group<ComputedDynamicMessageDiscountItem> DYNAMIC_MESSAGE_DISCOUNTS_ONSHIPPING = group(DYNAMIC_MESSAGE_DISCOUNTS, "ONSHIPPING");
        public final GroupSet<ComputedMoneyItem> ORDER_DISCOUNTS_ONSHIPPING = groupset("ORDER_DISCOUNTS_ONSHIPPING");
        public final GroupSet<ComputedMoneyItem> BUCKET_DISCOUNTS_ONSHIPPING = groupset("BUCKET_DISCOUNTS_ONSHIPPING");
        public final GroupSet<ComputedMoneyItem> PLI_DISCOUNTS_ONSHIPPING = groupset("PLI_DISCOUNTS_ONSHIPPING");
        public final GroupSet<ComputedPercentageItem> SHIPPING_PERCENTAGES_ONSHIPPING = groupset("SHIPPING_PERCENTAGES_ONSHIPPING");
        public final GroupSet<ComputedQuantityItem> PLI_DISCOUNTED_ITEM_QUANTITIES_ONSHIPPING = groupset("PLI_DISCOUNTED_ITEM_QUANTITIES_ONSHIPPING");
        public final GroupSet<ComputedMoneyItem> PLI_SINGLE_DISCOUNTS_ONSHIPPING = groupset("PLI_SINGLE_DISCOUNTS_ONSHIPPING");
        public final GroupSet<ComputedMoneyItem> PLI_TARGET_PRICES_ONSHIPPING = groupset("PLI_TARGET_PRICES_ONSHIPPING");
        public final GroupSet<ComputedMoneyItem> BUCKET_TARGET_PRICES_ONSHIPPING = groupset("BUCKET_TARGET_PRICES_ONSHIPPING");
        public final GroupSet<ComputedMoneyItem> ORDER_TARGET_PRICES_ONSHIPPING = groupset("ORDER_TARGET_PRICES_ONSHIPPING");


        public Promotion(final String prefix)
        {
            super(prefix);
        }

        @Override
        protected void defineRules()
        {
            addRule("calculateItemDiscounts", new PromotionCalculationRule(
                            in(PLI.PLIS),
                            in(PLI.GROSS_BASE_PRICES),
                            in(PLI.SINGLE_BASE_PRICES),
                            in(PLI.SUBTOTALS_BASE_GROSS),
                            in(SHIPPING.PLI_GROSS_BASE_COSTS),
                            in(SHIPPING.BUCKET_COSTS),
                            in(SHIPPING.BUCKETS),
                            in(SHIPPING.TOTALS_GROSS),
                            new ItemValueOffOutParams(
                                            out(APPLIED_DISCOUNTS_ONITEM),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONITEM),
                                            out(PLI_SINGLE_DISCOUNTS_ONITEM),
                                            out(GROSS_PLI_DISCOUNTS_ONITEM),
                                            out(PLI_DISCOUNTED_ITEM_QUANTITIES_ONITEM)),
                            new ItemPercentageOffOutParams(
                                            out(APPLIED_DISCOUNTS_ONITEM),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONITEM),
                                            out(PLI_SINGLE_DISCOUNTS_ONITEM),
                                            out(GROSS_PLI_DISCOUNTS_ONITEM),
                                            out(PLI_DISCOUNTED_ITEM_PERCENTAGES_ONITEM),
                                            out(PLI_DISCOUNTED_ITEM_QUANTITIES_ONITEM)),
                            new ItemTargetPriceOutParams(
                                            out(APPLIED_DISCOUNTS_ONITEM),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONITEM),
                                            out(PLI_SINGLE_DISCOUNTS_ONITEM),
                                            out(GROSS_PLI_DISCOUNTS_ONITEM),
                                            out(PLI_DISCOUNTED_ITEM_TARGET_PRICES_ONITEM),
                                            out(PLI_DISCOUNTED_ITEM_QUANTITIES_ONITEM)),
                            new ShippingValueOffOutParams(
                                            out(APPLIED_DISCOUNTS_ONSHIPPING),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONSHIPPING),
                                            out(ORDER_DISCOUNTS_ONSHIPPING),
                                            out(BUCKET_DISCOUNTS_ONSHIPPING),
                                            out(PLI_SINGLE_DISCOUNTS_ONSHIPPING),
                                            out(PLI_DISCOUNTS_ONSHIPPING),
                                            out(PLI_DISCOUNTED_ITEM_QUANTITIES_ONSHIPPING)),
                            new ShippingPercentageOffOutParams(
                                            out(APPLIED_DISCOUNTS_ONSHIPPING),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONSHIPPING),
                                            out(ORDER_DISCOUNTS_ONSHIPPING),
                                            out(BUCKET_DISCOUNTS_ONSHIPPING),
                                            out(PLI_SINGLE_DISCOUNTS_ONSHIPPING),
                                            out(PLI_DISCOUNTS_ONSHIPPING),
                                            out(SHIPPING_PERCENTAGES_ONSHIPPING),
                                            out(PLI_DISCOUNTED_ITEM_QUANTITIES_ONSHIPPING)),
                            new ShippingTargetPriceOutParams(
                                            out(APPLIED_DISCOUNTS_ONSHIPPING),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONSHIPPING),
                                            out(ORDER_DISCOUNTS_ONSHIPPING),
                                            out(ORDER_TARGET_PRICES_ONSHIPPING),
                                            out(BUCKET_DISCOUNTS_ONSHIPPING),
                                            out(BUCKET_TARGET_PRICES_ONSHIPPING),
                                            out(PLI_SINGLE_DISCOUNTS_ONSHIPPING),
                                            out(PLI_TARGET_PRICES_ONSHIPPING),
                                            out(PLI_DISCOUNTS_ONSHIPPING),
                                            out(PLI_DISCOUNTED_ITEM_QUANTITIES_ONSHIPPING)),
                            new OrderPercentageOffOutParams(
                                            out(APPLIED_DISCOUNTS_ONORDERVALUE),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONORDERVALUE),
                                            out(ORDER_VALUE_DISCOUNTS_ONORDERVALUE),
                                            out(ORDER_PERCENTAGES_ONORDERVALUE),
                                            out(PLI_SINGLE_DISCOUNTS_ONORDERVALUE),
                                            out(PLI_DISCOUNTS_ONORDERVALUE),
                                            out(PLI_DISCOUNTED_ITEM_QUANTITIES_ONORDERVALUE)),
                            new OrderValueOffOutParams(
                                            out(APPLIED_DISCOUNTS_ONORDERVALUE),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONORDERVALUE),
                                            out(ORDER_VALUE_DISCOUNTS_ONORDERVALUE),
                                            out(PLI_SINGLE_DISCOUNTS_ONORDERVALUE),
                                            out(PLI_DISCOUNTS_ONORDERVALUE),
                                            out(PLI_DISCOUNTED_ITEM_QUANTITIES_ONORDERVALUE)),
                            new FreeGiftOutParams(
                                            out(APPLIED_DISCOUNTS_ONGIFT),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONGIFT),
                                            out(SINGLE_ITEM_DISCOUNTS_ONGIFT),
                                            out(ITEM_DISCOUNTS_ONGIFT),
                                            out(DISCOUNTED_ITEM_TARGET_PRICES_ONGIFT),
                                            out(BONUS_PRODUCTS_ONGIFT),
                                            out(DISCOUNTED_ITEM_QUANTITIES_ONGIFT)),
                            new HiddenGiftOutParams(
                                            out(APPLIED_DISCOUNTS_ONHIDDENGIFT),
                                            out(APPLIED_DISCOUNT_AMOUNTS),
                                            out(DYNAMIC_MESSAGE_DISCOUNTS_ONHIDDENGIFT),
                                            out(SINGLE_ITEM_DISCOUNTS_ONHIDDENGIFT),
                                            out(ITEM_DISCOUNTS_ONHIDDENGIFT),
                                            out(DISCOUNTED_ITEM_TARGET_PRICES_ONHIDDENGIFT),
                                            out(BONUS_PRODUCTS_ONHIDDENGIFT),
                                            out(DISCOUNTED_ITEM_QUANTITIES_ONHIDDENGIFT))
                                        ));

            addRule("calculateShippingDiscountTotal", new AddMoneyRule(out(SHIPPING.TOTALS_DISCOUNT), in(PLI_DISCOUNTS_ONSHIPPING)));
            addRule("calculatePLIDiscountTotal", new AddMoneyRule(out(PLI.SUBTOTALS_DISCOUNT), in(GROSS_PLI_DISCOUNTS_ONITEM)));
            addRule("calculateOrderValueDiscount", new AddMoneyRule(out(ORDER.VALUE_DISCOUNT), in(ORDER_VALUE_DISCOUNTS_ONORDERVALUE)));
            addRule("calculateDiscountTotal", new AddMoneyRule(out(TOTAL.DISCOUNT), in(SHIPPING.TOTALS_DISCOUNT),
                            in(PLI.SUBTOTALS_DISCOUNT), in(ORDER.VALUE_DISCOUNT)));

        }

    }

    public static class Order extends LineItemCtnrCalculationRuleGroup
    {
        public final Group<ComputedMoneyItem>         VALUE_SUBTOTALS     = group("VALUE_SUBTOTALS");
        public final Cell<ComputedMoneyItem>          VALUE_GROSS           = cell(VALUE_SUBTOTALS, "Order_Gross");
        public final Cell<ComputedMoneyItem>          VALUE_TAX           = cell(VALUE_SUBTOTALS, "Tax");
        public final Cell<ComputedMoneyItem>          VALUE_DISCOUNT      = cell(VALUE_SUBTOTALS, "Discount");
        public final Cell<ComputedMoneyItem>          VALUE_RAW_DISCOUNTED_TAX = cell(VALUE_SUBTOTALS, "RawDiscountedTax");
        public final Cell<ComputedPercentageItem>     VALUE_DISCOUNT_RATE = cell(VALUE_SUBTOTALS.getGroup() + "_DISCOUNT_RATE", "DiscountRate");

        public Order(final String prefix)
        {
            super(prefix);
        }

        @Override
        protected void defineRules()
        {
            addRule("calculateOrderValueGross", new AddMoneyRule(out(VALUE_GROSS), in(PLI.SUBTOTALS_GROSS), in(VALUE_DISCOUNT), in(PLI.SUBTOTALS_DISCOUNT)));
            addRule("calculateOrderValueTax", new AddMoneyRule(out(VALUE_TAX), in(PLI.SUBTOTALS_TAX)));
        }

    }

    /**
     * The Class Payment bundles all payment computed items.
     */
    public static class Payment extends LineItemCtnrCalculationRuleGroup
    {
        /** The open tender payment instruments (PIIs)
         * this is an intermediate group whose final content will be in group OPEN_TENDER_PIIS */
        private final transient Group<ComputedServiceLineItem> OPEN_TENDER_PIIS_V1 = group("Open_PIIS_V1");
        /** The limited tender payment instruments (PIIs)
         *  this is an intermediate group whose final content will be in group LIMITED_TENDER_PIIS */
        private final transient Group<ComputedServiceLineItem> LIMITED_TENDER_PIIS_V1 = group("Limited_PIIS_V1");

        /** The open tender payment instruments (PIIs) excluding the ones that
         * need to be deleted (see PIIS_TO_BE_DELETED) */
        public final Group<ComputedPaymentInstrumentItem> OPEN_TENDER_PIIS = group("Open_PIIS");
        /** The limited tender payment instruments (PIIs) excluding the ones that
         * need to be deleted (see PIIS_TO_BE_DELETED) */
        public final Group<ComputedPaymentInstrumentItem> LIMITED_TENDER_PIIS = group("Limited_PIIS");

        /** The open tender PIIs pre base amounts */
        private final transient Group<ComputedMoneyItem> OPEN_TENDER_PIIS_PREBASEAMOUNT = group("Open_PIIS_PreBaseAmount");
        /** The limited tender PIIs pre base amounts */
        private final transient Group<ComputedMoneyItem> LIMITED_TENDER_PIIS_PREBASEAMOUNT = group("Limited_PIIS_PreBaseAmount");

        /** The open tender PIIs base amounts */
        public final Group<ComputedMoneyItem> OPEN_TENDER_PIIS_BASEAMOUNT = group("Open_PIIS_BaseAmount");
        /** The limited tender PIIs  base amounts */
        public final Group<ComputedMoneyItem> LIMITED_TENDER_PIIS_BASEAMOUNT = group("Limited_PIIS_BaseAmount");

        /** The open tender PIIs payment costs */
        public final Group<ComputedMoneyItem> OPEN_TENDER_PIIS_PAYMENT_COSTS = group("Open_PIIS_Cost");
        /** The limited tender PIIs payment costs */
        public final Group<ComputedMoneyItem> LIMITED_TENDER_PIIS_PAYMENT_COSTS = group("Limited_PIIS_Cost");

        /** The open tender PIIs payment taxes */
        public final Group<ComputedMoneyItem> OPEN_TENDER_PIIS_PAYMENT_TAXES = group("Open_PIIS_Taxes");
        /** The limited tender PIIs payment taxes */
        public final Group<ComputedMoneyItem> LIMITED_TENDER_PIIS_PAYMENT_TAXES = group("Limited_PIIS_Taxes");

        /** The open tender PIIs payment total amount (sum of payment base amount and payment surcharges) */
        public final Group<ComputedMoneyItem> OPEN_TENDER_PIIS_TOTAL = group("Open_PIIS_Total");
        /** The limited tender PIIs payment total amount (sum of payment base amount and payment surcharges) */
        public final Group<ComputedMoneyItem> LIMITED_TENDER_PIIS_TOTAL = group("Limited_PIIS_Total");

        /** The payment instrument info objects that need to be deleted because
         * the calculation process determined them to be unnecessary */
        public final Group<ComputedServiceLineItem> PIIS_TO_BE_DELETED = group("PIIS_To_Be_Deleted");


        /** The payment sub totals. */
        public final Group<ComputedMoneyItem> SUBTOTALS = group("SUBTOTALS");
        /** The totals payment cost (cost includes taxes!) */
        public final Cell<ComputedMoneyItem> TOTALS_COST = cell(SUBTOTALS, "Cost");
        /** The totals payment tax. */
        public final Cell<ComputedMoneyItem> TOTALS_TAX = cell(SUBTOTALS, "Tax");
        /** The totals payment amount covered by all payment instruments. */
        public final Cell<ComputedMoneyItem> TOTALS_COVERED_LIMITED = cell(SUBTOTALS, "Covered_Limited");
        /** The totals payment amount covered by all payment instruments. */
        public final Cell<ComputedMoneyItem> TOTALS_COVERED = cell(SUBTOTALS, "Covered");

        /**
         * Instantiates a new payment.
         *
         * @param groupPrefix
         *            the group prefix
         */
        private Payment(final String groupPrefix)
        {
            super(groupPrefix);
        }

        @Override
        public void defineRules()
        {
            // distribute basket total amount (excluding payment surcharges) over PIIs
            addRule("distributePaymentAmount", new DistributeBasketTotalAmountRule(out(OPEN_TENDER_PIIS_V1), out(LIMITED_TENDER_PIIS_V1),
                                                                                    out(OPEN_TENDER_PIIS_PREBASEAMOUNT), out(LIMITED_TENDER_PIIS_PREBASEAMOUNT),
                                                                                    in(TOTAL.TOTALS_GROSS_WITHOUT_PAYMENTSURCHARGES)));

            // calculate payment payment base amount, costs an payment taxes
            addRule("calculatePaymentAmounts", new CalculatePaymentSurchargesRule(CalculatePaymentSurchargesRule.CalculationType.GROSS, out(PIIS_TO_BE_DELETED),
                                                                                out(OPEN_TENDER_PIIS), out(LIMITED_TENDER_PIIS),
                                                                                out(OPEN_TENDER_PIIS_BASEAMOUNT), out(LIMITED_TENDER_PIIS_BASEAMOUNT),
                                                                                out(OPEN_TENDER_PIIS_PAYMENT_COSTS), out(LIMITED_TENDER_PIIS_PAYMENT_COSTS),
                                                                                out(OPEN_TENDER_PIIS_PAYMENT_TAXES), out(LIMITED_TENDER_PIIS_PAYMENT_TAXES),
                                                                                in(OPEN_TENDER_PIIS_PREBASEAMOUNT), in(LIMITED_TENDER_PIIS_PREBASEAMOUNT),
                                                                                in(OPEN_TENDER_PIIS_V1), in(LIMITED_TENDER_PIIS_V1)));
            // calculate payment totals cost
            addRule("calculatePaymentTotalCost", new AddMoneyRule(out(TOTALS_COST), in(OPEN_TENDER_PIIS_PAYMENT_COSTS), in(LIMITED_TENDER_PIIS_PAYMENT_COSTS)));

            // calculate payment totals tax
            addRule("calculatePaymentTotalTax", new AddMoneyRule(out(TOTALS_TAX), in(OPEN_TENDER_PIIS_PAYMENT_TAXES), in(LIMITED_TENDER_PIIS_PAYMENT_TAXES)));

            // calculate open tender payment totals
            addRule("calculateOpenPaymentTotals", new CalculateGroupAddMoneyRule(out(OPEN_TENDER_PIIS_TOTAL),
                                                                         in(OPEN_TENDER_PIIS_BASEAMOUNT), in(OPEN_TENDER_PIIS_PAYMENT_COSTS)));
            // calculate limited tender payment totals
            addRule("calculateLimitedPaymentTotals", new CalculateGroupAddMoneyRule(out(LIMITED_TENDER_PIIS_TOTAL),
                                                                         in(LIMITED_TENDER_PIIS_BASEAMOUNT), in(LIMITED_TENDER_PIIS_PAYMENT_COSTS)));

            // calculate the totals payment amount covered by all payment instruments. */
            addRule("calculateAllPaymentTotals", new AddMoneyRule(out(TOTALS_COVERED),
                                                                         in(OPEN_TENDER_PIIS_TOTAL), in(LIMITED_TENDER_PIIS_TOTAL)));
            
            // calculate the totals payment amount covered by limited tender payment instruments. */
            addRule("calculateLimitedPaymentTotalsCell", new AddMoneyRule(out(TOTALS_COVERED_LIMITED), in(LIMITED_TENDER_PIIS_TOTAL)));
            /*
             * copy the total payment amount of a PII to its amountForpayment attribute
             * should be reworked for IS11
             */
            addRule("copyAmountForPaymentLimited", new CopyMoneyAmountToPII(in(LIMITED_TENDER_PIIS), in(LIMITED_TENDER_PIIS_TOTAL)));
            addRule("copyAmountForPaymentOpen", new CopyMoneyAmountToPII(in(OPEN_TENDER_PIIS), in(OPEN_TENDER_PIIS_TOTAL)));

            // delete payment instruments not needed anymore */
            addRule("deleteUnusedPiis", new DeleteObsoletePIIs(in(PIIS_TO_BE_DELETED)));
        }
    }

    public static class Tax extends LineItemCtnrCalculationRuleGroup
    {
        public final Group<ComputedErrorItem> ERRORS = group("ERRORS");
        
        public final Group<ComputedMoneyItem> PAYMENT_COSTS = group("PAYMENT_COSTS");
        
        public final Cell<ComputedErrorItem> ERROR_TAX_DUTY_FEE = cell(ERRORS, "ERROR_TAX_DUTY_FEE");
        public Tax(final String prefix)
        {
            super(prefix);
        }

        @Override
        protected void defineRules()
        {
            addRule("calculateSimplePaymentCosts", new DetermineRoughPaymentCostsRule(out(PAYMENT_COSTS)));
            
            addRule("taxDutyCalculationService", new TaxesDutiesCalculationServiceRule(
                            TaxesDutiesCalculationServiceRule.CalculationMode.GROSS,
                            out(ERROR_TAX_DUTY_FEE),

                            out(PLI.TAX_RATES),
                            out(PLI.TAX_PRICES),
                            out(PLI.TAX_INFO),

                            out(PLI.ITEM_DISCOUNT_TAX_INFOS),
                            out(PLI.ORDER_DISCOUNT_TAX_INFOS),
                            out(SHIPPING.DISCOUNT_TAX_INFOS),
                            out(PROMOTION.NET_DISCOUNT_AMOUNTS),

                            out(GIFTING.PLI_TAX_RATES),
                            out(GIFTING.PLI_TAXES),
                            out(GIFTING.PLI_TAX_INFO),

                            out(WARRANTY.PLI_TAX_RATES),
                            out(WARRANTY.PLI_TAXES),
                            out(WARRANTY.PLI_TAX_INFO),

                            out(CONFIGURATION.PLI_TAX_RATES),
                            out(CONFIGURATION.PLI_TAXES),
                            out(CONFIGURATION.PLI_TAX_INFO),

                            out(SHIPPING.PLI_TAX_RATES),
                            out(SHIPPING.PLI_TAX_COSTS),
                            out(SHIPPING.PLI_TAX_INFO),

                            out(PLI.DUTY_CHARGES),
                            out(PLI.DUTY_INFO),
                            out(SHIPPING.PLI_GEOGRAPHICAL_SURCHARGE_TAX_COSTS),
                            out(SHIPPING.PLI_GEOGRAPHICAL_SURCHARGE_TAX_INFO),
                            out(SHIPPING.PLI_IMPORT_SURCHARGE_TAX_COSTS),
                            out(SHIPPING.PLI_IMPORT_SURCHARGE_TAX_INFO),

                            in(PLI.PLIS),
                            in(PLI.ROOT_PLIS),
                            in(PLI.SINGLE_BASE_PRICES),
                            in(PLI.GROSS_BASE_PRICES),

                            in(PROMOTION.GROSS_PLI_DISCOUNTS_ONITEM),
                            in(PROMOTION.APPLIED_DISCOUNTS_ONITEM),
                            in(PROMOTION.PLI_DISCOUNTS_ONORDERVALUE),
                            in(PROMOTION.APPLIED_DISCOUNTS_ONORDERVALUE),

                            in(PROMOTION.PLI_DISCOUNTS_ONSHIPPING),
                            in(PROMOTION.APPLIED_DISCOUNTS_ONSHIPPING),

                            in(GIFTING.FILTERED_PLIS),
                            in(GIFTING.PLI_SINGLE_PRICES),
                            in(GIFTING.PLI_GROSS_PRICES),

                            in(WARRANTY.FILTERED_PLIS),
                            in(WARRANTY.PLI_SINGLE_PRICES),
                            in(WARRANTY.PLI_GROSS_PRICES),

                            in(CONFIGURATION.FILTERED_PLIS),
                            in(CONFIGURATION.PLI_SINGLE_PRICES),
                            in(CONFIGURATION.PLI_GROSS_PRICES),

                            in(SHIPPING.PLI_GROSS_BASE_COSTS),
                            in(SHIPPING.PLI_GEOGRAPHICAL_SURCHARGES),
                            in(SHIPPING.PLI_GEOGRAPHICAL_SURCHARGE_COSTS),
                            in(SHIPPING.PLI_IMPORT_SURCHARGES),
                            in(SHIPPING.PLI_IMPORT_SURCHARGE_COSTS)));

            addRule("calculatePLITaxes", new AddMoneyRule(
                            out(PLI.TAXES),
                            in(PLI.TAX_PRICES),
                            in(SHIPPING.PLI_TAX_COSTS),
                            in(SHIPPING.PLI_GEOGRAPHICAL_SURCHARGE_TAX_COSTS),
                            in(SHIPPING.PLI_IMPORT_SURCHARGE_TAX_COSTS)));
            addRule("calculatePLIDuties", new AddMoneyRule(out(PLI.DUTIES), in(PLI.DUTY_CHARGES)));
            addRule("calculatePLISurcharges", new AddMoneyRule(out(PLI.SURCHARGES), in(SHIPPING.PLI_GEOGRAPHICAL_SURCHARGE_COSTS), in(SHIPPING.PLI_IMPORT_SURCHARGE_COSTS)));

            addRule("calculatePLISubtotalsTax", new AddMoneyRule(out(PLI.SUBTOTALS_BASE_TAX), in(PLI.TAXES)));
            addRule("calculatePLISubtotalsDuty", new AddMoneyRule(out(PLI.SUBTOTALS_DUTY), in(PLI.DUTIES)));
            addRule("calculatePLISubtotalsSurcharge", new AddMoneyRule(out(PLI.SUBTOTALS_SURCHARGE), in(PLI.SURCHARGES)));

            addRule("calculateTotalPerTaxType", new CalculateTotalPerTaxTypeRule(
                            out(TOTAL.TAX_PER_TYPE),
                            in(PLI.TAX_INFO),
                            in(SHIPPING.PLI_TAX_INFO),
                            in(SHIPPING.PLI_GEOGRAPHICAL_SURCHARGE_TAX_INFO),
                            in(SHIPPING.PLI_IMPORT_SURCHARGE_TAX_INFO)));
            addRule("calculateTotalPerDutyType", new CalculateTotalPerDutyTypeRule(
                            out(TOTAL.DUTY_PER_TYPE),
                            in(PLI.DUTY_INFO)));
        }
    }

    public static class BonusPoint extends LineItemCtnrCalculationRuleGroup
    {
        public final Group<ComputedProductLineItem>   BPP_PLIS                  = group("BPP_PLIS");

        public BonusPoint(final String prefix)
        {
            super(prefix);
        }

        @Override
        protected void defineRules()
        {
            addRule("initalizeBonusPointPricePLIs", new CreateInitialProductItemsRule(out(BPP_PLIS), 1));
            addRules("calculateBonusPointPriceTotal", new BonusPointCalculation("BPP", out(TOTAL.BPP), in(BPP_PLIS)));
            addRules("calculateBonusPointValueTotal", new BonusPointCalculation("BPV", out(TOTAL.BPV), in(PLI.PLIS)));
        }
    }

    public static class Pli extends LineItemCtnrCalculationRuleGroup
    {
        /*** Product line items ***/
        public final Group<ComputedProductLineItem>   ROOT_PLIS              = group("INITIALPLIS");
        public final Group<ComputedProductLineItem>   PLIS                      = group("PLIS");

        /*** Product base prices ***/
        public final Group<ComputedMoneyItem>         SINGLE_BASE_PRICES_WITHOUT_CUSTOM_GIFTCARDS    = group("SINGLE_BASE_PRICES");
        public final Group<ComputedMoneyItem>         SINGLE_BASE_PRICES    = group("SINGLE_BASE_PRICES");

        /*** Line item prices ***/
        public final Group<ComputedMoneyItem>         RAW_BASE_PRICES       = group("RAW_BASE_PRICES");
        public final Group<ComputedMoneyItem>         GROSS_BASE_PRICES       = group("GROSS_BASE_PRICES");
        /**  Net prices (without discounts) */
        public final Group<ComputedMoneyItem>         NET_BASE_PRICES       = group("NET_BASE_PRICES");
        /**  Net prices with discounts  */
        public final Group<ComputedMoneyItem>         DISCOUNT_SUMS         = group("DISCOUNT_SUMS");
        public final Group<ComputedMoneyItem>         GROSS_PRICES            = group("GROSS_PRICES");
        public final Group<ComputedMoneyItem>         TAXES                 = group("TAXES");
        public final Group<ComputedMoneyItem>         DUTIES                = group("DUTIES");
        public final Group<ComputedMoneyItem>         SURCHARGES            = group("SURCHARGES");

        /** Taxes applied to (line) item price */
        public final GroupSet<ComputedTaxInfoItem>    TAX_INFO              = groupset("TAX_INFO.#");
        public final GroupSet<ComputedTaxInfoItem>    ITEM_DISCOUNT_TAX_INFOS   = groupset("ITEM_DISCOUNT_TAX_INFOS.#");
        public final GroupSet<ComputedTaxInfoItem>    ORDER_DISCOUNT_TAX_INFOS  = groupset("ORDER_DISCOUNT_TAX_INFOS.#");

        public final GroupSet<ComputedPercentageItem> TAX_RATES             = groupset("TAX_RATES.#");
        public final GroupSet<ComputedMoneyItem>      TAX_PRICES            = groupset("TAX_PRICES.#");
        public final Group<ComputedMoneyItem>         TAX_PLI_PRICES       = group("TAX_PLI_PRICES");

        public final Group<ComputedMoneyItem>         SUBTOTALS             = group("SUBTOTALS");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_DISCOUNT    = cell(SUBTOTALS, "Discount");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_DISCOUNT_TAX    = cell(SUBTOTALS, "DiscountTax");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_DISCOUNT_NET    = cell(SUBTOTALS, "DiscountNet");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_GROSS         = cell(SUBTOTALS, "Gross");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_GROSS_WITH_DISCOUNT = cell(SUBTOTALS, "GrossWithDiscount");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_BASE_GROSS    = cell(SUBTOTALS, "BaseGross");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_BASE_TAX         = cell(SUBTOTALS, "BaseTax");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_TAX         = cell(SUBTOTALS, "Tax");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_DUTY        = cell(SUBTOTALS, "Duty");
        public final Cell<ComputedMoneyItem>          SUBTOTALS_SURCHARGE    = cell(SUBTOTALS, "Surcharge");

        /*** Duties ***/
        public final GroupSet<ComputedTaxInfoItem>    DUTY_INFO             = groupset("DUTY_INFO.#");
        public final GroupSet<ComputedMoneyItem>      DUTY_CHARGES          = groupset("DUTY_CHARGES.#");

        public Pli(final String prefix)
        {
            super(prefix);
        }

        @Override
        protected void defineRules()
        {
            addRule("initalizePLIs", new CreateInitialProductItemsRule(out(PLI.ROOT_PLIS), 0));
            addRule("determineProductItemSingleBasePrices", new CalculateSingleProductBasePricesRule(out(PLI.SINGLE_BASE_PRICES), in(PLI.ROOT_PLIS), false));
            addRule("determineProductItemSingleBasePrices", new CustomCalculateSingleProductBasePricesRule(out(PLI. SINGLE_BASE_PRICES_WITHOUT_CUSTOM_GIFTCARDS), in(PLI.ROOT_PLIS), false));
            addRule("determinePLIsWithPrice", new DetermineProductItemsWithPriceRule(out(PLI.PLIS),in(PLI.SINGLE_BASE_PRICES), in(PLI.ROOT_PLIS)));
            addRule("calculateProductItemRawBasePrices", new MultiplyMoneyWithQuantityRule(out(PLI.RAW_BASE_PRICES), in(PLI.SINGLE_BASE_PRICES), in(PLI.PLIS)));
            addRule("calculateProductItemGrossBasePrices", new RoundMoneyRule(out(PLI.GROSS_BASE_PRICES), in(PLI.RAW_BASE_PRICES)));
            addRule("calculateProductItemDiscountSums", new AddMoneyRule(out(PLI.DISCOUNT_SUMS), in(PROMOTION.GROSS_PLI_DISCOUNTS_ONITEM)));
            addRule("calculateProductItemShippingDiscountSums", new AddMoneyRule(out(SHIPPING.PLI_GROSS_COSTS), in(SHIPPING.PLI_GROSS_BASE_COSTS), in(PROMOTION.PLI_DISCOUNTS_ONSHIPPING)));
            addRule("calculateProductItemGrossPrices", new AddMoneyRule(out(PLI.GROSS_PRICES), in(PLI.GROSS_BASE_PRICES), in(PLI.DISCOUNT_SUMS)));
            addRule("calculateProductItemGrossTotal", new AddMoneyRule(out(PLI.SUBTOTALS_GROSS), in(PLI.GROSS_BASE_PRICES), in(PLI.SUBTOTALS_SURCHARGE), in(WARRANTY.TOTALS_GROSS)));
            addRule("calculateProductItemGrossTotalWithDiscount", new AddMoneyRule(out(SUBTOTALS_GROSS_WITH_DISCOUNT), in(SUBTOTALS_GROSS), in(SUBTOTALS_DISCOUNT)));
            addRule("calculateProductItemBaseGrossTotal", new AddMoneyRule(out(SUBTOTALS_BASE_GROSS), in(GROSS_BASE_PRICES)));

            addRule("calculatePliTaxes", new AddMoneyRule(out(TAX_PLI_PRICES), in(TAX_PRICES)));
            addRule("calculateProductItemNetBasePrices", new SubtractMoneyRule(out(NET_BASE_PRICES), in(GROSS_BASE_PRICES), in(TAX_PLI_PRICES)));
            addRule("sumTotalDiscountNet", new AddMoneyRule(out(SUBTOTALS_DISCOUNT_NET), in(PROMOTION.NET_DISCOUNT_AMOUNTS)));
            addRule("calculateDiscountTax", new AddMoneyRule(out(SUBTOTALS_DISCOUNT_TAX), in(TOTAL.DISCOUNT), in(SUBTOTALS_DISCOUNT_NET)));
            addRule("calculateTax", new AddMoneyRule(out(SUBTOTALS_TAX), in(SUBTOTALS_BASE_TAX), in(SUBTOTALS_DISCOUNT_TAX)));
        }
    }

    /**
     * The Class Gifting.
     */
    public static class Gifting extends LineItemCtnrCalculationRuleGroup
    {
        /** The gifting product line items. */
        public final SubGroup<ComputedProductLineItem, ComputedProductLineItem> PLIS = subGroup(PLI.ROOT_PLIS, "PLIS");
        /** The filtered gifting product line items (having a price). */
        public final SubGroup<ComputedProductLineItem, ComputedProductLineItem> FILTERED_PLIS = subGroup(PLI.ROOT_PLIS, "FILTERED_PLIS");
        /** The quantities. */
        public final SubGroup<ComputedProductLineItem, ComputedQuantityItem> PLI_QUANTITIES = subGroup(PLI.ROOT_PLIS, "PLI_QUANTITIES");
        /** The base prices. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem> PLI_BASE_PRICES = subGroup(PLI.ROOT_PLIS, "PLI_BASE_PRICES");
        /** The gross prices. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem> PLI_GROSS_PRICES = subGroup(PLI.ROOT_PLIS, "PLI_GROSS_PRICES");
        /** The raw prices. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem> PLI_RAW_PRICES = subGroup(PLI.ROOT_PLIS, "PLI_PRICES");
        /** The single prices. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem> PLI_SINGLE_PRICES = subGroup(PLI.ROOT_PLIS, "PLI_SINGLE_PRICES");
        /** The discounts. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem> PLI_DISCOUNTS_ONITEM = subGroup(PLIS, "PLI_DISCOUNTS_ONITEM");
        private final SubGroup<ComputedProductLineItem, ComputedMoneyItem> PLI_DISCOUNT_SUMS = subGroup(PLI.ROOT_PLIS, "PLI_DISCOUNT_SUMS");
        /** The TOTAL gross. */
        public final Cell<ComputedMoneyItem> TOTALS_GROSS = cell(PLI.SUBTOTALS, "TOTALS_GIFTING_GROSS");
        /** The taxes. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem> PLI_TAXES = subGroup(FILTERED_PLIS, "PLI_TAXES");
        /** The taxes rates. */
        public final SubGroup<ComputedProductLineItem, ComputedPercentageItem> PLI_TAX_RATES = subGroup(FILTERED_PLIS, "PLI_TAX_RATES");
        /** Taxes applied to gifting items */
        public final SubGroup<ComputedProductLineItem, ComputedTaxInfoItem> PLI_TAX_INFO = subGroup(FILTERED_PLIS, "TAX_INFO");

        /**
         * Instantiates a new gifting.
         *
         * @param groupName the group name
         */
        public Gifting(final String groupName)
        {
            super(groupName);
        }

        @Override
        protected void defineRules()
        {
            addRule("initalizePlis", new CreateChildProductItemsRule(out(PLIS), in(PLI.ROOT_PLIS), LineItemConstants.GIFT_WRAP_SERVICE, LineItemConstants.GIFT_MESSAGE_SERVICE));
            addRule("calculateSinglePrice", new CalculateSingleProductBasePricesRule(out(PLI_SINGLE_PRICES), in(PLIS), false));
            addRule("filterPlis", new DetermineProductItemsWithPriceRule(out(FILTERED_PLIS), in(PLI_SINGLE_PRICES), in(PLIS)));
            addRule("calculateQuantities", new ComputeQuantityRule(out(PLI_QUANTITIES), in(PLI.ROOT_PLIS), in(FILTERED_PLIS)));
            addRule("calculatePrices", new MultiplyMoneyWithQuantityRule(out(PLI_RAW_PRICES), in(PLI_SINGLE_PRICES),in(PLI_QUANTITIES)));
            addRule("roundPrices", new RoundMoneyRule(out(PLI_BASE_PRICES), in(PLI_RAW_PRICES)));
            addRule("calculateDiscounts", new DummyRule(out(PLI_DISCOUNTS_ONITEM), in(PLI_BASE_PRICES)));
            addRule("calculateDiscountOnItem", new AddMoneyRule(out(PLI_DISCOUNT_SUMS), in(PLI_DISCOUNTS_ONITEM)));
            addRule("calculateGrossPrices", new AddMoneyRule(out(PLI_GROSS_PRICES), in(PLI_BASE_PRICES), in(PLI_DISCOUNT_SUMS)));
            addRule("calculateTotalGross", new AddMoneyRule(out(TOTALS_GROSS), in(PLI_GROSS_PRICES)));
        }
    }

    /**
     * The Class Warranty.
     */
    public static class Warranty extends LineItemCtnrCalculationRuleGroup
    {
        /** The warranty plis. */
        public final SubGroup<ComputedProductLineItem, ComputedProductLineItem>  PLIS       = subGroup(PLI.ROOT_PLIS, "PLIS");
        /** The filtered warranty product line items (having a price). */
        public final SubGroup<ComputedProductLineItem, ComputedProductLineItem> FILTERED_PLIS = subGroup(PLI.ROOT_PLIS, "FILTERED_PLIS");
        /** The single prices. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem>        PLI_SINGLE_PRICES   = subGroup(PLI.ROOT_PLIS, "PLI_SINGLE_PRICES");
        /** The quantity. */
        public final SubGroup<ComputedProductLineItem, ComputedQuantityItem>        PLI_QUANITY      = subGroup(PLI.ROOT_PLIS, "PLI_QUANTITY");
        /** The gross prices. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem>        PLI_GROSS_PRICES      = subGroup(PLI.ROOT_PLIS, "PLI_GROSS_PRICES");
        /** The taxes. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem>        PLI_TAXES           = subGroup(PLI.ROOT_PLIS, "PLI_TAXES");
        /** The taxes rates. */
        public final SubGroup<ComputedProductLineItem, ComputedPercentageItem> PLI_TAX_RATES = subGroup(FILTERED_PLIS, "PLI_TAX_RATES");
        /** Taxes applied to gifting items */
        public final SubGroup<ComputedProductLineItem, ComputedTaxInfoItem> PLI_TAX_INFO = subGroup(FILTERED_PLIS, "TAX_INFO");
        /** The TOTAL gross. */
        public final Cell<ComputedMoneyItem>         TOTALS_GROSS          = cell(PLI.SUBTOTALS, "TOTALS_WARRANTY_GROSS");

        /**
         * Instantiates a new warranty.
         *
         * @param groupPrefix the group prefix
         */
        public Warranty(final String groupPrefix)
        {
            super(groupPrefix);
        }

        @Override
        public void defineRules()
        {
            addRule("initalizeWarrantyPlis", new CreateChildProductItemsRule(out(PLIS), in(PLI.ROOT_PLIS), WarrantyLineItemBO.WARRANTY));
            addRule("calculateWarrantySinglePrice", new CreateWarrantyPricesRule(out(PLI_SINGLE_PRICES), in(PLIS)));
            addRule("filterWarrantyPlis", new DetermineProductItemsWithPriceRule(out(FILTERED_PLIS), in(PLI_SINGLE_PRICES), in(PLIS)));
            addRule("calculateWarrantyQuantity", new ComputeQuantityRule(out(PLI_QUANITY), in(PLI.ROOT_PLIS), in(FILTERED_PLIS)));
            addRule("calculateWarrantyGross", new MultiplyMoneyWithQuantityRule(out(PLI_GROSS_PRICES), in(PLI_SINGLE_PRICES), in(PLI_QUANITY)));
            addRule("calculateTotalWarrantyGross", new AddMoneyRule(out(TOTALS_GROSS), in(PLI_GROSS_PRICES)));
        }
    }

    /**
     * The Class Configuration.
     * Calculates all configurable and customizable products
     */
    public static class Configuration extends LineItemCtnrCalculationRuleGroup
    {
        /** The configuration plis. */
        public final SubGroup<ComputedProductLineItem, ComputedProductLineItem>  PLIS       = subGroup(PLI.ROOT_PLIS, "PLIS");
        /** The filtered configuration product line items (having a price). */
        public final SubGroup<ComputedProductLineItem, ComputedProductLineItem> FILTERED_PLIS = subGroup(PLI.ROOT_PLIS, "FILTERED_PLIS");
        /** The single prices. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem>        PLI_SINGLE_PRICES   = subGroup(PLI.ROOT_PLIS, "PLI_SINGLE_PRICES");
        /** The quanity. */
        public final SubGroup<ComputedProductLineItem, ComputedQuantityItem>        PLI_QUANITY      = subGroup(PLI.ROOT_PLIS, "PLI_QUANTITY");
        /** The raw gross prices = quantity * single price*/
        private final SubGroup<ComputedProductLineItem, ComputedMoneyItem> PLI_RAW_PRICES = subGroup(PLI.ROOT_PLIS,
        "PLI_RAW_PRICES");
        /** The gross prices. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem>        PLI_GROSS_PRICES      = subGroup(PLI.ROOT_PLIS, "PLI_GROSS_PRICES");
        /** The taxes. */
        public final SubGroup<ComputedProductLineItem, ComputedMoneyItem>        PLI_TAXES           = subGroup(PLI.ROOT_PLIS, "PLI_TAXES");
        /** The taxes rates. */
        public final SubGroup<ComputedProductLineItem, ComputedPercentageItem> PLI_TAX_RATES = subGroup(FILTERED_PLIS, "PLI_TAX_RATES");
        /** Taxes applied to gifting items */
        public final SubGroup<ComputedProductLineItem, ComputedTaxInfoItem> PLI_TAX_INFO = subGroup(FILTERED_PLIS, "TAX_INFO");
        /** The total of all configuration items. */
        public final Cell<ComputedMoneyItem> TOTALS_GROSS = cell(PLI.SUBTOTALS, "TOTALS_CONFIGURATION_GROSS");

        /**
         * Instantiates a new configuration.
         *
         * @param groupPrefix the string
         */
        public Configuration(final String groupPrefix)
        {
            super(groupPrefix);
        }

        @Override
        protected void defineRules()
        {
            addRule("initalizeConfigurationPlis", new CreateChildProductItemsRule(out(PLIS), in(PLI.ROOT_PLIS), ProductConfigurationLineItemBO.PRODUCTCONFIGURATION));
            addRule("calculateConfigurationSinglePrice", new CalculateSingleProductBasePricesRule(out(PLI_SINGLE_PRICES), in(PLIS), false));
            addRule("filterConfigurationPlis", new DetermineProductItemsWithPriceRule(out(FILTERED_PLIS), in(PLI_SINGLE_PRICES), in(PLIS)));
            addRule("calculateConfigurationQuantity", new ComputeQuantityRule(out(PLI_QUANITY), in(PLI.ROOT_PLIS), in(FILTERED_PLIS)));
            addRule("calculateConfigurationRaw", new MultiplyMoneyWithQuantityRule(out(PLI_RAW_PRICES), in(PLI_SINGLE_PRICES), in(PLI_QUANITY)));
            addRule("calculateConfigurationGross", new RoundMoneyRule(out(PLI_GROSS_PRICES), in(PLI_RAW_PRICES)));
            addRule("addTotals", new AddMoneyRule(out(TOTALS_GROSS), in(PLI_GROSS_PRICES)));
        }
    }

    @Override
    protected void defineRules()
    {
        addRules(PLI);
        addRules(SHIPPING);
        addRules(PAYMENT);
        addRules(ORDER);
        addRules(PROMOTION);
        addRules(TOTAL);
        addRules(TAX);
        addRules(BONUS_POINT);
        addRules(CONFIGURATION);
        addRules(WARRANTY);
        addRules(GIFTING);
    }
}